package cn.huixh.blindbox.exception;

import cn.huixh.blindbox.common.ResultData;
import cn.huixh.blindbox.common.ReturnCode;
import cn.huixh.blindbox.exception.impl.BizException;
import cn.hutool.jwt.JWTException;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * @author huixh
 * @version 1.0
 * @date 2022/5/6 19:00
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {


    /**
     * 参数丢失异常
     *
     * @param req 请求
     * @param e   异常
     * @return 结果
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResultData< String > paramLostException(HttpServletRequest req, MissingServletRequestParameterException e) {
        log.error("参数丢失：{}", e.getMessage());
        return ResultData.error(ReturnCode.RC205);
    }

    /**
     * @param req 请求
     * @param e   异常
     * @return 结果
     */
    @ExceptionHandler(value = MissingRequestHeaderException.class)
    public ResultData< String > tokenLostException(HttpServletRequest req, MissingServletRequestParameterException e) {
        log.error("请求头丢失：{}", e.getMessage());
        return ResultData.error(ReturnCode.RC205);
    }

    /**
     * 业务异常
     *
     * @param req 请求
     * @param e   异常
     * @return 结果
     */
    @ExceptionHandler(value = BizException.class)
    public ResultData< String > argsLoss(HttpServletRequest req, BizException e) {
        log.error("业务异常：{}", e.getMessage());
        return ResultData.error(e.getErrorCode(), e.getErrorMsg());
    }

    /**
     * @param req 请求
     * @param e   异常
     * @return 结果
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ResultData< String > illegalArgumentException(HttpServletRequest req, IllegalArgumentException e) {
        log.error("参数异常：{}", e.getMessage());
        return ResultData.error(ReturnCode.RC205);
    }

    /**
     * 坏的请求方式
     *
     * @return 结果
     */
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResultData< ReturnCode > badRequest(HttpRequestMethodNotSupportedException e) {
        log.error("错误的方法请求：{}", e.getMessage());
        return ResultData.error(ReturnCode.RC404);
    }

    @ResponseStatus(HttpStatus.EXPECTATION_FAILED)
    @ExceptionHandler(value = JWTException.class)
    public ResultData< ReturnCode > jwtException(JWTException exception) {
        log.error("token 验证失败：{}", exception.getMessage());
        return ResultData.error(ReturnCode.INVALID_TOKEN);
    }

    /**
     * 其他异常
     *
     * @param request 请求
     * @param e       异常
     * @return 结果
     */
    @ExceptionHandler(value = Exception.class)
    public ResultData< String > exception(HttpServletRequest request, Exception e) {
        log.error("未知异常！{}", e.getMessage());
        e.printStackTrace();
        return ResultData.error(500, "未知异常！");
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResultData handle1(ConstraintViolationException ex) {
        StringBuilder msg = new StringBuilder();
        Set< ConstraintViolation< ? > > constraintViolations = ex.getConstraintViolations();
        for (ConstraintViolation< ? > constraintViolation : constraintViolations) {
            PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
            String paramName = pathImpl.getLeafNode().getName();
            String message = constraintViolation.getMessage();
            msg.append("[").append(message).append("]");
        }
        log.error(msg.toString(), ex);

        return ResultData.error(msg.toString());
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResultData handle2(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        if (bindingResult != null) {
            if (bindingResult.hasErrors()) {
                FieldError fieldError = bindingResult.getFieldError();
                String field = fieldError.getField();
                String defaultMessage = fieldError.getDefaultMessage();
                log.error(ex.getMessage(), ex);
                return ResultData.error(field + ":" + defaultMessage);
            } else {
                log.error(ex.getMessage(), ex);
                return ResultData.error(ReturnCode.RC500);
            }
        } else {
            log.error(ex.getMessage(), ex);
            return ResultData.error(ReturnCode.RC500);
        }
    }

}
